.\"
.\" Copyright (C) 2004-2008, 2013 Richard Kettlewell
.\"
.\" This program is free software: you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
.\" the Free Software Foundation, either version 3 of the License, or
.\" (at your option) any later version.
.\" 
.\" This program is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
.\" GNU General Public License for more details.
.\" 
.\" You should have received a copy of the GNU General Public License
.\" along with this program.  If not, see <http://www.gnu.org/licenses/>.
.\"
.TH disorder 3
.SH NAME
disorder \- plugin interface to DisOrder jukebox
.SH SYNOPSIS
.B "#include <disorder.h>"
.SH DESCRIPTION
This header file defines the plugin interface to DisOrder.
.PP
The first half of this man page describes the functions DisOrder
provides to plugins; the second half describes the functions that
plugins must provide.
.SH "MEMORY ALLOCATION"
DisOrder uses a garbage collector internally.
Therefore it is recommended that plugins use the provided memory
allocation interface, rather than calling \fBmalloc\fR(3) etc directly.
.PP
.nf
\fBvoid *disorder_malloc(size_t);
void *disorder_realloc(void *, size_t);
.fi
.IP
These functions behave much like \fBmalloc\fR(3) and \fBrealloc\fR(3)
except that they never fail; they always zero out the memory
allocated; and you do not need to free the result.
.IP
They may still return a null pointer if asked for a 0-sized
allocation.
.PP
.nf
\fBvoid *disorder_malloc_noptr(size_t);
void *disorder_realloc_noptr(void *, size_t);
.fi
.IP
These functions are like \fBmalloc\fR(3) and \fBrealloc\fR(3)
except that they never fail and you must not put any pointer
values in the allocated memory.
.IP
They may still return a null pointer if asked for a 0-sized
allocation.
They do not guarantee to zero out the memory allocated.
.PP
.nf
\fBchar *disorder_strdup(const char *);
char *disorder_strndup(const char *, size_t);
.fi
.IP
These functions are like \fBstrdup\fR(3) and \fBstrndup\fR(3) except
that they never fail and you do not need to free the result.
.PP
.nf
\fBint disorder_asprintf(char **rp, const char *fmt, ...);
int disorder_snprintf(char buffer[], size_t bufsize,
                      const char *fmt, ...);
.fi
.IP
These function are like \fBsnprintf\fR(3) and \fBasprintf\fR(3).
.B disorder_asprintf
never fails on memory allocation and
you do not need to free the results.
.IP
Floating point conversions and wide character support are not
currently implemented.
.IP
These functions will cope with UTF-8 even if the current locale uses
some other encoding.
.PP
"Never fail" in the above means that the process is terminated on error.
.SH LOGGING
Standard error doesn't reliably go anywhere in current versions of DisOrder,
and whether syslog is to be used varies depending on how the program is
invoked.
Therefore plugins should use these functions to log any errors or
informational messages.
.PP
.nf
\fBvoid disorder_error(int errno_value, const char *fmt, ...);
.fi
.IP
Log an error message.
If \fBerrno_value\fR is not 0 then the relevant
string is included in the error message.
.PP
.nf
\fBvoid disorder_fatal(int errno_value, const char *fmt, ...);
.fi
.IP
Log an error message and then terminate the process.
If \fBerrno_value\fR is not 0 then the relevant string is included in the
error message.
.IP
.B disorder_fatal
is the right way to terminate the process if a fatal error arises.
You shouldn't usually try to use \fBexit\fR(3) or \fB_exit\fR(2).
.PP
.nf
\fBvoid disorder_info(const char *fmt, ...);
.fi
.IP
Log a message.
.IP
.SH "TRACK DATABASE"
The functions in this section provide a way of accessing the track database.
In server plugins these access the database directly; in client plugins the
requests are transmitted to the server over a socket.
.PP
All strings in this section are encoded using UTF-8.
.PP
.nf
\fBint disorder_track_exists(const char *track);
.fi
.IP
This function returns non-0 if \fBtrack\fR exists and 0 if it does
not.
.PP
.nf
\fBconst char *disorder_track_get_data(const char *track,
                                    const char *key);
.fi
.IP
This function looks up the value of \fBkey\fR for \fBtrack\fR and
returns a pointer to a copy of it.
Do not bother to free the pointer.
If the track or key are not found a null pointer is returned.
.PP
.nf
\fBint disorder_track_set_data(const char *track,
                            const char *key,
                            const char *value);
.fi
.IP
This function sets the value of \fBkey\fR for \fBtrack\fR to
\fBvalue\fR.
On success, 0 is returned; on error, \-1 is returned.
.IP
If \fBvalue\fR is a null pointer then the preference is deleted.
.IP
Values starting with an underscore are stored in the tracks database,
and are lost if the track is deleted; they should only ever have
values that can be regenerated on demand.
Other values are stored in the prefs database and never get
automatically deleted.
.SH "PLUGIN FUNCTIONS"
This section describes the functions that you must implement to write various
plugins.
All of the plugins have at least one standard implementation available
in the DisOrder source.
.PP
Some functions are listed as only available in server plugins.
Currently this means that they are not even defined outside the
server.
.PP
All strings in this section are encoded using UTF-8.
.SS "Tracklength Plugins"
These are server plugins defined by the \fBtracklength\fR directive.
.PP
.nf
\fBlong disorder_tracklength(const char *track,
                          const char *path);
.fi
.IP
Called to calculate the length of a track.
\fBtrack\fR is the track name (UTF-8) and \fBpath\fR is the path
name if there was one, or a null pointer otherwise.
\fBpath\fR will be the same byte string return from
the scanner plugin, and so presumably encoded according to the
filesystem encoding.
.IP
To clarify this point, if the track must be opened to compute its
length, you would normally use \fBpath\fR and not \fBtrack\fR.
.IP
If the return value is positive it should be the track length in
seconds (round up if it is not an integral number of seconds long).
.IP
If the return value is zero then the track length is unknown.
.IP
If the return value is negative then an error occurred determining the
track length.
.PP
Tracklength plugins are invoked from a subprocess of the server, so
they can block without disturbing the server's operation.
.SS notify.so
This is a server plugin.
.PP
.nf
\fBvoid disorder_notify_play(const char *track,
                          const char *submitter);
.fi
.IP
Called when \fBtrack\fR is about to be played.
\fBsubmitter\fR identifies the submitter or is a null pointer if
the track was picked for random play.
.PP
.nf
\fBvoid disorder_notify_scratch(const char *track,
                             const char *submitter,
                             const char *scratcher,
                             int seconds);
.fi
.IP
Called when \fBtrack\fR is scratched by \fBscratcher\fR.
\fBsubmitter\fR identifies the submitter or is a null pointer if
the track was picked for random play.
\fBseconds\fR is the number of seconds since the track started playing.
.PP
.nf
\fBvoid disorder_notify_not_scratched(const char *track,
                                   const char *submitter);
.fi
.IP
Called when \fBtrack\fR completes without being scratched (an error might have
occurred though).
\fBsubmitter\fR identifies the submitter or is a null pointer if the
track was picked for random play.
.PP
.nf
\fBvoid disorder_notify_queue(const char *track,
                           const char *submitter);
.fi
.IP
Called when \fBtrack\fR is added to the queue by \fBsubmitter\fR
(which is never a null pointer).
Not called for scratches.
.PP
.nf
\fBvoid disorder_notify_queue_remove(const char *track,
                                  const char *remover);
.fi
.IP
Called when \fBtrack\fR is removed from queue by \fBremover\fR (which
is never a null pointer).
.PP
.nf
\fBvoid disorder_notify_queue_move(const char *track,
                                const char *remover);
.fi
.IP
Called when \fBtrack\fR is moved in the queue by \fBmover\fR
(which is never a null pointer).
.PP
.nf
\fBvoid disorder_notify_pause(const char *track,
                           const char *who);
.fi
.IP
Called when \fBtrack\fR is paused by \fBwho\fR
(which might be a null pointer).
.PP
.nf
\fBvoid disorder_notify_resume(const char *track,
                            const char *who);
.fi
.IP
Called when \fBtrack\fR is resumed by \fBwho\fR
(which might be a null pointer).
.SS "Scanner Plugins"
Scanner plugins are server plugins and may have any name; they are
chosen via the configuration file.
.PP
.nf
\fBvoid disorder_scan(const char *root);
.fi
.IP
Write a list of files below \fBroot\fR to standard output.
Each filename should be in the encoding defined for this root in the
configuration file and should be terminated by character 0.
.IP
It is up to the plugin implementor whether they prefer to use stdio or
write to file descriptor 1 directly.
.IP
All the filenames had better start with \fBroot\fR as this is used to
match them back up to the right collection to call
\fBdisorder_check\fR on.
.PP
.nf
\fBint disorder_check(const char *root, const char *path);
.fi
.IP
Check whether file \fBpath\fR under \fBroot\fR still exists.
Should return 1 if it exists, 0 if it does not and \-1 on error.
This is run in the main server process.
.PP
Both scan and recheck are executed inside a subprocess, so it will not
break the server if they block for an extended period (though of
course, they should not gratuitously take longer than necessary to do
their jobs).
.SS "Player plugins"
Player plugins are server plugins and may have any name; they are
chosen via the configuration file.
.PP
.nf
extern const unsigned long disorder_player_type;
.fi
.IP
This defines the player type and capabilities.
It should consist of a single type value ORed with any number of
capability values.
The following are known type values:
.RS
.TP
.B DISORDER_PLAYER_STANDALONE
A standalone player that writes directly to some suitable audio
device.
.TP
.B DISORDER_PLAYER_RAW
A player that writes blocks of raw samples to \fB$DISORDER_RAW_FD\fR.
See
.B "RAW FORMAT PLAYERS"
below.
.RE
.IP
Known capabilities are:
.RS
.TP
.B DISORDER_PLAYER_PREFORK
Supports the prefork and cleanup calls.
.TP
.B DISORDER_PLAYER_PAUSES
Supports the pause and resume calls.
.RE
.PP
.nf
\fBvoid *disorder_play_prefork(const char *track);
.fi
.IP
Called before a track is played, if \fB_PREFORK\fR is set.
\fBtrack\fR is the name of the track in UTF-8.
This function must never block, as it runs inside the main loop of the server.
.IP
The return value will be passed to the functions below as \fBdata\fR.
On error, a null pointer should be returned.
.PP
.nf
\fBvoid disorder_play_cleanup(void *data);
.fi
.IP
Called after a track has been completed, if \fB_PREFORK\fR is set, for
instance to release the memory used by \fBdata\fR.
This function must never block, as it runs inside the main loop of the server.
.PP
.nf
\fBvoid disorder_play_track(const char *const *parameters,
                         int nparameters,
                         const char *path,
                         const char *track,
                         void *data);
.fi
.IP
Play a track.
.IP
\fBpath\fR is the path name as originally encoded in the filesystem.
This is the value you should ultimately pass to \fBopen\fR(2).
.IP
\fBtrack\fR is the path name converted to UTF-8.
This value (possibly converted to some other encoding) should be used
in any logs, etc.
.IP
If there is no meaningful path, or if the track is a scratch (where no
filename encoding information is available), \fBpath\fR will be equal
to \fBtrack\fR.
.IP
The parameters are any additional arguments
supplied to the \fBplayer\fR configuration file command.
.IP
This function is always called inside a fork, and it should not return
until playing has finished.
.IP
DisOrder sends the subprocess a signal if the track is to be scratched
(and when \fBdisorderd\fR is shut down).
By default this signal is \fBSIGKILL\fR but it can be reconfigured.
.PP
.nf
\fBint disorder_play_pause(long *playedp,
                        void *data);
.fi
.IP
Pauses the current track, for players that support pausing.
This function must never block, as it runs inside the main loop of the
server.
.IP
On success, should return 0 and set \fB*playedp\fR to the number of
seconds played so far of this track, or to \-1 if this cannot be
determined.
.IP
On error, should return \-1.
.PP
.nf
\fBvoid disorder_play_resume(void *data);
.fi
.IP
Resume playing the current track after a pause.
This function must never block, as it runs inside the main loop of the server.
.SH "RAW FORMAT PLAYERS"
Raw format players should write data to the file descriptor given by
the environment variable \fBDISORDER_RAW_FD\fR.
.PP
The output format is a series of chunks.  Each chunk has a header with
the following format:
.PP
.nf
struct stream_header {
  uint32_t nbytes;
  uint32_t rate;
  uint8_t channels;
  uint8_t bits;
  uint8_t endian;
} attribute((packed));
.fi
.PP
The meanings of the fields are as follows:
.TP
.B nbytes
The total number of bytes of sample data that follow the header.
.TP
.B rate
The sample rate in samples per second.
e.g. 44100.
.TP
.B channels
The number of channels per frame.
e.g. 2.
.TP
.B bits
The number of bits per sample.
e.g. 16.
.TP
.B endian
The sample byte order.
1 for big-endian samples and 2 for little-endian samples.
.PP
Any number of chunks are allowed.
.PP
Raw format players may be started before the track is to be played,
and (if the track is then removed from the queue before it reaches the
head) terminated before the track ever reaches a physical speaker.
The point of this is to allow audio data to be ready to play the
moment the previous track end, without having to wait for the player
to start up.
There is no way for a player to tell that this is going on.
.SH NOTES
There is no special DisOrder library to link against; the symbols are
exported by the executables themselves.
(You should NOT try to link against \fB-ldisorder\fR.)
Plugins must be separately
linked against any other libraries they require, even if the DisOrder
executables are already linked against them.
.PP
The easiest approach is probably to develop the plugin inside the
DisOrder tree; then you can just use DisOrder's build system.
This might also make it easier to submit patches if you write something of
general utility.
.PP
Failing that you can use Libtool, if you make sure to pass the
\fB-module\fR option.
For current versions of DisOrder you only need the shared object
itself, not the \fB.la\fR file.
.PP
If you know the right runes for your toolchain you could also build
the modules more directly.
.PP
It is possible, up to a point, to implement several plugin interfaces
from within a single shared object.
If you ever use any of the functions that are listed as only being
available in server plugins, though, then you can only use the
resulting shared object as a server plugin.
.SH "SEE ALSO"
.BR disorderd (8),
.BR disorder (1),
.BR disorder_config (5)
.\" Local Variables:
.\" mode:nroff
.\" End:
